package com.my.study.utils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.my.study.enums.BusinessExceptionEnum;
import com.my.study.exception.BusinessException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.*;
import org.springframework.stereotype.Component;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.HttpServerErrorException;
import org.springframework.web.client.RestTemplate;

import javax.annotation.PostConstruct;
import java.util.*;

@Slf4j
@Component
public class RestTemplateUtil {

    private static RestTemplate restTemplate;

    @Autowired
    private RestTemplate httpsTemplate;

    @PostConstruct
    public void afterPropertiesSet() {
        RestTemplateUtil.restTemplate = httpsTemplate;
    }

    /**
     * Get发送简单请求，不含body
     *
     * @param url
     * @param urlParam
     * @return
     */
    public static String doGet(String url, Map<String, String> urlParam) {
        return doGet(url, urlParam, null, new ParameterizedTypeReference<String>() {
        });
    }

    public static JSONObject doGet(String url, Map<String, String> urlParam, Map<String, String> header) {
        return doGet(url, urlParam, header, new ParameterizedTypeReference<JSONObject>() {
        });
    }

    public static <T> T doGet(String url, Map<String, String> urlParam, Map<String, String> header,
                              ParameterizedTypeReference<T> responseType) {
        try {
            // url参数拼接
            url = handleUrlParam(url, urlParam);

            //填充属性到请求头
            HttpHeaders httpHeaders = new HttpHeaders();
            fillParamsToHttpHeader(header, httpHeaders);
            HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(null, httpHeaders);

            // 发送请求
            ResponseEntity<T> responseEntity = restTemplate.exchange(url, HttpMethod.GET, requestEntity, responseType);
            return responseEntity.getBody();
        } catch (Exception exception) {
            handlerException(exception);
            log.error("Get request failed" + exception);
            throw BusinessException.fail(BusinessExceptionEnum.FAIL.code, "get 请求失败！");
        }
    }

    /**
     * POST请求
     *
     * @param url
     * @param body
     * @return
     */
    public static JSONObject doPost(String url, Map<String, Object> body) {
        return doPost(url, null, body, new ParameterizedTypeReference<JSONObject>() {
        });
    }

    public static String doPost(String url, Map<String, String> head, Map<String, Object> body) {
        return doPost(url, head, body, new ParameterizedTypeReference<String>() {
        });
    }

    public static <T> T doPost(String url, Map<String, String> head, Object body,
                               ParameterizedTypeReference<T> responseType) {

        try {
            HttpHeaders httpHeaders = new HttpHeaders();
            // 设置请求内容为json
            httpHeaders.setContentType(MediaType.APPLICATION_JSON);
            // 添加头部信息
            fillParamsToHttpHeader(head, httpHeaders);
            // 创建请求实体
            HttpEntity<Object> httpEntity = new HttpEntity<>(JSON.toJSONString(body), httpHeaders);
            // 执行请求
            ResponseEntity<T> responseEntity = restTemplate.exchange(url, HttpMethod.POST, httpEntity, responseType);
            return responseEntity.getBody();
        } catch (Exception exception) {
            handlerException(exception);
            log.error("Post request failed" + exception);
            throw BusinessException.fail(BusinessExceptionEnum.FAIL.code, "Post 请求失败！");
        }
    }

    /**
     * 异常处理
     *
     * @param exception
     */
    private static void handlerException(Exception exception) {
        if (exception instanceof HttpServerErrorException) {
            HttpServerErrorException serverErrorException = (HttpServerErrorException) exception;
            JSONObject jsonObject = JsonUtil.jsonToObject(serverErrorException.getResponseBodyAsString(), JSONObject.class);
            log.error("Get request failed" + serverErrorException);
            throw BusinessException.fail(jsonObject.getString("resultCode"), jsonObject.getString("resultMsg"));
        }
    }

    /**
     * url参数拼接
     *
     * @param url
     * @param urlParam
     * @return
     */
    private static String handleUrlParam(String url, Map<String, String> urlParam) {
        // 判空
        if (urlParam == null || urlParam.isEmpty()) {
            return url;
        }
        // url参数拼接
        Iterator<Map.Entry<String, String>> iterator = urlParam.entrySet().iterator();
        StringBuilder urlBuilder = new StringBuilder(url);
        urlBuilder.append("?");
        while (iterator.hasNext()) {
            Map.Entry<String, String> entry = iterator.next();
            urlBuilder.append(entry.getKey()).append("=").append(entry.getValue()).append("&");
        }
        urlBuilder.deleteCharAt(urlBuilder.length() - 1);
        return String.valueOf(urlBuilder);
    }

    /**
     * 填充参数到请求头
     *
     * @param heads
     * @param headers
     */
    public static void fillParamsToHttpHeader(Map<String, String> heads, HttpHeaders headers) {
        // 判断空
        if (Objects.isNull(heads)) {
            return;
        }
        // 头部填充
        Set<String> keySet = heads.keySet();
        for (String s : keySet) {
            if (headers.get(s) == null) {
                headers.add(s, "");
            } else {
                headers.add(s, String.valueOf(heads.get(s)));
            }
        }
    }

    /**
     * 表单提交，有请求头和请求体 指定请求方式
     *
     * @param url
     * @param urlParam
     * @param body
     * @param method
     * @return
     */
    public static String sendForm(String url, Map<String, String> urlParam, Map<String, Object> body, HttpMethod method) {
        return sendForm(url, urlParam, body, method, new HttpHeaders());
    }

    public static String sendForm(String url, Map<String, String> header, Map<String, Object> body,
                                  HttpMethod method, HttpHeaders headers) {
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        return send(url, header, body, method, headers, null);
    }

    public static String sendForm(String url, Map<String, String> header, Map<String, Object> body,
                                  HttpMethod method, HttpHeaders headers, Map<String, String> urlParam) {
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        return send(url, header, body, method, headers, urlParam);
    }

    /**
     * 复杂请求发送
     *
     * @param url      url
     * @param head     请求头
     * @param body     请求体
     * @param method   请求方式
     * @param headers  实际请求头
     * @param urlParam 用?和&拼接在url后面的参数
     */
    public static String send(String url, Map<String, String> head, Map<String, Object> body, HttpMethod method,
                              HttpHeaders headers, Map<String, String> urlParam) {
        try {
            if (urlParam == null) {
                urlParam = new HashMap<>(16);
            }
            // Get 请求 url参数拼接
            if (method.equals(HttpMethod.GET)) {
                url = handleUrlParam(url, urlParam);
            }

            //填充参数到Http请求头
            fillParamsToHttpHeader(head, headers);

            log.info("请求地址为: " + url);

            if (Objects.equals(headers.getContentType(), MediaType.APPLICATION_JSON)) {
                String str = null;
                if (Objects.isNull(body)) {
                    str = new JSONObject().toJSONString();
                } else {
                    JSONObject jsonObject = new JSONObject();
                    jsonObject.putAll(body);
                    str = jsonObject.toJSONString();
                }
                HttpEntity<String> requestEntity = new HttpEntity<>(str, headers);
                return restTemplate.postForEntity(url, requestEntity, String.class).getBody();
            }
            if (Objects.equals(headers.getContentType(), MediaType.APPLICATION_FORM_URLENCODED)) {
                // body参数处理
                MultiValueMap<String, String> param = new LinkedMultiValueMap<>();
                for (Map.Entry<String, ?> next : body.entrySet()) {
                    param.add(next.getKey(), (String) next.getValue());
                }

                HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(param, headers);
                return restTemplate.exchange(url, method, requestEntity, String.class, urlParam).getBody();
            }
        } catch (Exception e) {
            log.error(e.getMessage());
            e.printStackTrace();
        }
        return null;
    }

}

